package br.com.vendaext.gerencial.apresentacao;

import java.lang.reflect.ParameterizedType;
import java.sql.BatchUpdateException;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.swing.text.AbstractDocument.Content;

import org.hibernate.Hibernate;
import org.hibernate.exception.ConstraintViolationException;
import org.primefaces.component.dialog.Dialog;
import org.primefaces.event.SelectEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;

import com.sun.org.apache.bcel.internal.generic.SALOAD;
import com.sun.org.apache.xalan.internal.xsltc.compiler.sym;
import com.sun.xml.bind.CycleRecoverable.Context;

import br.com.vendaext.gerencial.aop.Cronometrar;
import br.com.vendaext.gerencial.aop.HideException;
import br.com.vendaext.gerencial.entidades.Entidade;
import br.com.vendaext.gerencial.entidades.Perfil;
import br.com.vendaext.gerencial.entidades.Permissao;
import br.com.vendaext.gerencial.entidades.Usuario;
import br.com.vendaext.gerencial.integracao.DAOGenerico;
import br.com.vendaext.gerencial.integracao.PermissaoDAO;
import br.com.vendaext.gerencial.util.WebUtil;

@SuppressWarnings("unchecked")
public abstract class GenericHome<T extends Entidade> {

	private DAOGenerico daoPrincipal;

	private T entidade;

	boolean estadoCadastrando = false;
	boolean estadoEditando = false;
	boolean permiteIncluir = false;
	boolean permiteAtualizar = false;
	boolean permiteExcluir = false;
	boolean permitePesquisar = false;

	// quando foi selecionado um registro na busca
	private boolean estadoSelecionado = false;

	public List<T> getTodos() {
		return daoPrincipal.listar();
	}

	public void atualizar() {
		daoPrincipal.salvar(entidade);
	}

	public void inserir() {
		daoPrincipal.inserir(entidade);
		FacesContext context = FacesContext.getCurrentInstance();
		if (estadoEditando)
			context.addMessage("", new FacesMessage("Atualizado com sucesso"));
		else
			context.addMessage("", new FacesMessage("Inserido com sucesso"));
	}

	public void excluir() {
		try{
			daoPrincipal.excluir(entidade);
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage("", new FacesMessage("Excluído com sucesso"));
		}catch (DataAccessException e) {
			if (e.getMostSpecificCause() instanceof BatchUpdateException){
				addError("Operação não realizada", ((BatchUpdateException)e.getMostSpecificCause()).getNextException().getLocalizedMessage());
			}else
			addError("Operação não realizada", e.getMostSpecificCause().getLocalizedMessage());
		}
	}

	public DAOGenerico getDaoPrincipal() {
		return daoPrincipal;
	}

	public void setDaoPrincipal(DAOGenerico daoPrincipal) {
		this.daoPrincipal = daoPrincipal;
	}

	public T getEntidade() {
		return entidade;
	}

	public void setEntidade(T entidade) {
		this.entidade = entidade;
	}

	public boolean isEstadoCadastrando() {
		return estadoCadastrando;
	}

	public void setEstadoCadastrando(boolean estadoCadastrando) {
		this.estadoCadastrando = estadoCadastrando;
	}

	public boolean isEstadoEditando() {
		return estadoEditando;
	}

	public void setEstadoEditando(boolean estadoEditando) {
		this.estadoEditando = estadoEditando;
	}

	/**********************************************************/

	public abstract void checaRestricoes();

	public abstract void limparTela();

	public void selecionar(SelectEvent ev) {
		setEstadoCadastrando(false);
		setEstadoEditando(false);
		setEstadoSelecionado(true);
	}

	public void iniciarCadastrar(ActionEvent ev) {
		limparTela();
		setEstadoCadastrando(true);
		setEstadoEditando(false);
		setEstadoSelecionado(false);
	}

	// @HideException
	public void iniciarInserir(ActionEvent ev) {
		checaRestricoes();
		inserir();
		setEstadoCadastrando(false);
		setEstadoEditando(false);
		setEstadoSelecionado(true);
	}

	public void iniciarEditar(ActionEvent ev) {
		setEstadoEditando(true);
		setEstadoCadastrando(false);
		setEstadoSelecionado(false);
	}

	public void iniciarExcluir(ActionEvent ev) {
		excluir();
		setEstadoCadastrando(false);
		setEstadoEditando(false);
		setEstadoSelecionado(false);
		limparTela();
	}

	public void cancelar(ActionEvent ev) {
		setEstadoCadastrando(false);
		setEstadoEditando(false);
		setEstadoSelecionado(false);
		limparTela();
	}

	public boolean isEstadoSelecionado() {
		return estadoSelecionado;
	}

	public void setEstadoSelecionado(boolean estadoSelecionado) {
		this.estadoSelecionado = estadoSelecionado;
	}

	public void addInfo(String msg, String detail) {
		FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, detail));
	}

	public void addWarn(String msg, String detail) {
		FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, msg, detail));
	}

	public void addError(String msg, String detail) {
		FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, detail));
	}

	public void addFatal(String msg, String detail) {
		FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_FATAL, msg, detail));
	}

	protected Class<T> getTipoDaEntidade() {
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		return clazz;
	}

	public boolean isPermiteIncluir() {
		Perfil p = WebUtil.getUsuarioLogado().getPerfil();
		for (Permissao permissao : p.getPermissao()) {
			if (permissao.getModulo().getBean().equalsIgnoreCase(getClass().getSimpleName())
					&& permissao.getFuncionalidade().getNome().equalsIgnoreCase("Incluir")) {
				return true;
			}
		}
		return false;
	}

	public boolean isPermiteAtualizar() {
		Perfil p = WebUtil.getUsuarioLogado().getPerfil();
		for (Permissao permissao : p.getPermissao()) {
			if (permissao.getModulo().getBean().equalsIgnoreCase(getClass().getSimpleName())
					&& permissao.getFuncionalidade().getNome().equalsIgnoreCase("Alterar")) {
				return true;
			}
		}
		return false;
	}

	public boolean isPermiteExcluir() {
		Perfil p = WebUtil.getUsuarioLogado().getPerfil();
		for (Permissao permissao : p.getPermissao()) {
			if (permissao.getModulo().getBean().equalsIgnoreCase(getClass().getSimpleName())
					&& permissao.getFuncionalidade().getNome().equalsIgnoreCase("Excluir")) {
				return true;
			}
		}
		return false;
	}

	public boolean isPermitePesquisar() {
		Perfil p = WebUtil.getUsuarioLogado().getPerfil();
		for (Permissao permissao : p.getPermissao()) {
			if (permissao.getModulo().getBean().equalsIgnoreCase(getClass().getSimpleName())
					&& permissao.getFuncionalidade().getNome().equalsIgnoreCase("Pesquisar")) {
				return true;
			}
		}
		return false;
	}
}
